home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / DOMHDR.C < prev    next >
C/C++ Source or Header  |  1997-08-18  |  13KB  |  539 lines

  1. /* Domain header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Additional support for the Domain Name Server
  5.  * by Johan. K. Reinalda, WG7J,
  6.  * based on previous work by Gerard v.d. Grinten, PA0GRI
  7.  */
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "domain.h"
  11.  
  12. #if !defined(_lint)
  13. static char rcsid[] OPTIONAL = "$Id: domhdr.c,v 1.14 1997/08/19 01:19:22 root Exp root $";
  14. #endif
  15.  
  16. static int dn_expand (char *msg, char *eom, char *compressed, char *full, int fullen);
  17. static char *getq (struct rr ** rrpp, char *msg, char *cp);
  18. static char *ntohrr (struct rr ** rrpp, char *msg, char *cp);
  19.  
  20. #ifdef DSERVER
  21. static char *dn_compress (char *cp, char *name);
  22. static char *htonrr (struct rr * rr, char *buffer);
  23. #endif
  24.  
  25.  
  26. int
  27. ntohdomain (dhdr, bpp)
  28. register struct dhdr *dhdr;
  29. struct mbuf **bpp;
  30. {
  31. int16 tmp, len;
  32. register int16 i;
  33. char *msg, *cp;
  34. struct rr **rrpp;
  35.  
  36.     len = len_p (*bpp);
  37.     msg = mallocw ((unsigned) len);
  38.     (void) pullup (bpp, (unsigned char *) msg, len);
  39.     memset ((char *) dhdr, 0, sizeof (*dhdr));
  40.  
  41.     dhdr->id = get16 (&msg[0]);
  42.     tmp = get16 (&msg[2]);
  43.     if (tmp & 0x8000)
  44.         dhdr->qr = 1;
  45.     dhdr->opcode = (tmp >> 11) & 0xf;
  46.     if (tmp & 0x0400)
  47.         dhdr->aa = 1;
  48.     if (tmp & 0x0200)
  49.         dhdr->tc = 1;
  50.     if (tmp & 0x0100)
  51.         dhdr->rd = 1;
  52.     if (tmp & 0x0080)
  53.         dhdr->ra = 1;
  54.     dhdr->rcode = tmp & 0xf;
  55.     dhdr->qdcount = get16 (&msg[4]);
  56.     dhdr->ancount = get16 (&msg[6]);
  57.     dhdr->nscount = get16 (&msg[8]);
  58.     dhdr->arcount = get16 (&msg[10]);
  59.  
  60.     /* Now parse the variable length sections */
  61.     cp = &msg[12];
  62.  
  63.     /* Question section */
  64.     rrpp = &dhdr->questions;
  65.     for (i = 0; i < dhdr->qdcount; i++) {
  66.         if ((cp = getq (rrpp, msg, cp)) == NULLCHAR) {
  67.             free (msg);
  68.             return -1;
  69.         }
  70.         (*rrpp)->source = RR_QUESTION;
  71.         rrpp = &(*rrpp)->next;
  72.     }
  73.     *rrpp = NULLRR;
  74.  
  75.     /* Answer section */
  76.     rrpp = &dhdr->answers;
  77.     for (i = 0; i < dhdr->ancount; i++) {
  78.         if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
  79.             free (msg);
  80.             return -1;
  81.         }
  82.         (*rrpp)->source = RR_ANSWER;
  83.         rrpp = &(*rrpp)->next;
  84.     }
  85.     *rrpp = NULLRR;
  86.  
  87.     /* Name server (authority) section */
  88.     rrpp = &dhdr->authority;
  89.     for (i = 0; i < dhdr->nscount; i++) {
  90.         if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
  91.             free (msg);
  92.             return -1;
  93.         }
  94.         (*rrpp)->source = RR_AUTHORITY;
  95.         rrpp = &(*rrpp)->next;
  96.     }
  97.     *rrpp = NULLRR;
  98.  
  99.     /* Additional section */
  100.     rrpp = &dhdr->additional;
  101.     for (i = 0; i < dhdr->arcount; i++) {
  102.         if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
  103.             free (msg);
  104.             return -1;
  105.         }
  106.         (*rrpp)->source = RR_ADDITIONAL;
  107.         rrpp = &(*rrpp)->next;
  108.     }
  109.     *rrpp = NULLRR;
  110.     free (msg);
  111.     return 0;
  112. }
  113.  
  114.  
  115. static char *
  116. getq (rrpp, msg, cp)
  117. struct rr **rrpp;
  118. char *msg;
  119. char *cp;
  120. {
  121. register struct rr *rrp;
  122. int len;
  123. char *name;
  124.  
  125.     *rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
  126.  
  127.     name = mallocw (512);
  128.     len = dn_expand (msg, NULLCHAR, cp, name, 512);
  129.     if (len == -1) {
  130.         free (name);
  131.         return NULLCHAR;
  132.     }
  133.     cp += len;
  134.     rrp->name = strdup (name);
  135.     rrp->type = get16 (cp);
  136.     cp += 2;
  137.     rrp->class = get16 (cp);
  138.     cp += 2;
  139.     rrp->ttl = 0;
  140.     rrp->rdlength = 0;
  141.     free (name);
  142.     return cp;
  143. }
  144.  
  145.  
  146. /* Read a resource record from a domain message into a host structure */
  147. static char *
  148. ntohrr (rrpp, msg, cp)
  149. struct rr **rrpp;        /* Where to allocate resource record structure */
  150. char *msg;            /* Pointer to beginning of domain message */
  151. char *cp;            /* Pointer to start of encoded RR record */
  152. {
  153. register struct rr *rrp;
  154. int len;
  155. char *name;
  156.  
  157.     *rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
  158.  
  159.     name = mallocw (512);
  160.     if ((len = dn_expand (msg, NULLCHAR, cp, name, 512)) == -1) {
  161.         free (name);
  162.         return NULLCHAR;
  163.     }
  164.     cp += len;
  165.     rrp->name = strdup (name);
  166.     rrp->type = get16 (cp);
  167.     cp += 2;
  168.     rrp->class = get16 (cp);
  169.     cp += 2;
  170.     rrp->ttl = (int32) get32 (cp);
  171.     cp += 4;
  172.     rrp->rdlength = get16 (cp);
  173.     cp += 2;
  174.     switch (rrp->type) {
  175.         case TYPE_A:
  176.             /* Just read the address directly into the structure */
  177.             rrp->rdata.addr = get32 (cp);
  178.             cp += 4;
  179.             break;
  180.         case TYPE_CNAME:
  181.         case TYPE_MB:
  182.         case TYPE_MG:
  183.         case TYPE_MR:
  184.         case TYPE_NS:
  185.         case TYPE_PTR:
  186.             /* These types all consist of a single domain name;
  187.              * convert it to ascii format
  188.              */
  189.             len = dn_expand (msg, NULLCHAR, cp, name, 512);
  190.             if (len == -1) {
  191.                 free (name);
  192.                 return NULLCHAR;
  193.             }
  194.             rrp->rdata.name = strdup (name);
  195.             rrp->rdlength = (int16) strlen (name);
  196.             cp += len;
  197.             break;
  198.         case TYPE_HINFO:
  199.             len = *cp++;
  200.             rrp->rdata.hinfo.cpu = mallocw ((unsigned) len + 1);
  201.             memcpy (rrp->rdata.hinfo.cpu, cp, (size_t) len);
  202.             rrp->rdata.hinfo.cpu[len] = '\0';
  203.             cp += len;
  204.  
  205.             len = *cp++;
  206.             rrp->rdata.hinfo.os = mallocw ((unsigned) len + 1);
  207.             memcpy (rrp->rdata.hinfo.os, cp, (size_t) len);
  208.             rrp->rdata.hinfo.os[len] = '\0';
  209.             cp += len;
  210.             break;
  211.         case TYPE_MX:
  212.             rrp->rdata.mx.pref = get16 (cp);
  213.             cp += 2;
  214.             /* Get domain name of exchanger */
  215.             len = dn_expand (msg, NULLCHAR, cp, name, 512);
  216.             if (len == -1) {
  217.                 free (name);
  218.                 return NULLCHAR;
  219.             }
  220.             rrp->rdata.mx.exch = strdup (name);
  221.             cp += len;
  222.             break;
  223.         case TYPE_SOA:
  224.             /* Get domain name of name server */
  225.             len = dn_expand (msg, NULLCHAR, cp, name, 512);
  226.             if (len == -1) {
  227.                 free (name);
  228.                 return NULLCHAR;
  229.             }
  230.             rrp->rdata.soa.mname = strdup (name);
  231.             cp += len;
  232.  
  233.             /* Get domain name of responsible person */
  234.             len = dn_expand (msg, NULLCHAR, cp, name, 512);
  235.             if (len == -1) {
  236.                 free (name);
  237.                 return NULLCHAR;
  238.             }
  239.             rrp->rdata.soa.rname = strdup (name);
  240.             cp += len;
  241.  
  242.             rrp->rdata.soa.serial = (int32) get32 (cp);
  243.             cp += 4;
  244.             rrp->rdata.soa.refresh = (int32) get32 (cp);
  245.             cp += 4;
  246.             rrp->rdata.soa.retry = (int32) get32 (cp);
  247.             cp += 4;
  248.             rrp->rdata.soa.expire = (int32) get32 (cp);
  249.             cp += 4;
  250.             rrp->rdata.soa.minimum = (int32) get32 (cp);
  251.             cp += 4;
  252.             break;
  253.         case TYPE_TXT:
  254.             /* Just stash */
  255.             rrp->rdata.data = mallocw ((unsigned) rrp->rdlength);
  256.             memcpy (rrp->rdata.data, cp, (size_t) rrp->rdlength);
  257.             cp += rrp->rdlength;
  258.             break;
  259.         default:
  260.             /* Ignore */
  261.             cp += rrp->rdlength;
  262.             break;
  263.     }
  264.     free (name);
  265.     return cp;
  266. }
  267.  
  268.  
  269. /* Convert a compressed domain name to the human-readable form */
  270. static int
  271. dn_expand (msg, eom, compressed, full, fullen)
  272. char *msg;            /* Complete domain message */
  273. char *eom OPTIONAL;
  274. char *compressed;        /* Pointer to compressed name */
  275. char *full;            /* Pointer to result buffer */
  276. int fullen;            /* Length of same */
  277. {
  278. unsigned int slen;    /* Length of current segment */
  279. register char *cp;
  280. int clen = 0;        /* Total length of compressed name */
  281. int indirect = 0;    /* Set if indirection encountered */
  282. int nseg = 0;        /* Total number of segments in name */
  283.  
  284.     cp = compressed;
  285.     for (;;) {
  286.         slen = uchar (*cp++);    /* Length of this segment */
  287.         if (!indirect)
  288.             clen++;
  289.         if ((slen & 0xc0) == 0xc0) {
  290.             if (!indirect)
  291.                 clen++;
  292.             indirect = 1;
  293.             /* Follow indirection */
  294.             cp = &msg[((slen & 0x3f) << 8) + uchar (*cp)];
  295.             slen = uchar (*cp++);
  296.         }
  297.         if (slen == 0)    /* zero length == all done */
  298.             break;
  299.         fullen -= (int) (slen + 1);
  300.         if (fullen < 0)
  301.             return -1;
  302.         if (!indirect)
  303.             clen += (int) slen;
  304.         while (slen-- != 0)
  305.             *full++ = *cp++;
  306.         *full++ = '.';
  307.         nseg++;
  308.     }
  309.     if (nseg == 0) {
  310.         /* Root name; represent as single dot */
  311.         *full++ = '.';
  312.         fullen--;
  313.     }
  314.     *full++ = '\0';
  315.     fullen--;
  316.     return clen;        /* Length of compressed message */
  317. }
  318.  
  319.  
  320.  
  321. #ifdef DSERVER
  322.  
  323. /* Most of this code is based on the DNS server in PA0GRI's 910828
  324.  * Ported to the current NOS code by Johan. K. Reinalda, WG7J
  325.  * for version and bug/feature info, see domain.c
  326.  */
  327.  
  328. static char *
  329. dn_compress (cp, name)
  330. char *cp, *name;
  331. {
  332. int len, dlen;
  333. char *cp1;
  334. char *nametmp;
  335.  
  336.     if (!name)
  337.         return cp;
  338.     dlen = (int) strlen (name);
  339.     for (;;) {
  340.         /* Look for next dot */
  341.         cp1 = strchr (name, '.');
  342.         if (cp1 != NULLCHAR)
  343.             len = cp1 - name;    /* More to come */
  344.         else
  345.             len = dlen;    /* Last component */
  346.         *cp++ = (char) len;    /* Write length of component */
  347.         if (len == 0)
  348.             return cp;
  349.         /* Copy component up to (but not including) dot */
  350.         nametmp = name;
  351.         strncpy (cp, nametmp, (size_t) len);
  352.         cp += len;
  353.         if (cp1 == NULLCHAR) {
  354.             *cp++ = 0;    /* Last one; write null and finish */
  355.             return cp;
  356.         }
  357.         name += len + 1;
  358.         dlen -= len + 1;
  359.     }
  360. }
  361.  
  362.  
  363. /* Translate a resource record from host format to network format */
  364. static char *
  365. htonrr (rr, buffer)
  366. struct rr *rr;
  367. char *buffer;
  368. {
  369. struct rr *rrp;
  370. unsigned char *cp, *p;
  371. int i, len;
  372.  
  373.     cp = (unsigned char *) buffer;
  374.     for (rrp = rr; rrp != NULLRR; rrp = rrp->next) {
  375. #ifdef notdef
  376.         i = strlen (rrp->name);
  377.         if (rrp->name[i - 1] != '.'
  378.             && rrp->origin != NULLCHAR) {
  379.             p = mallocw (i + strlen (rrp->origin) + 2);
  380.             sprintf (p, "%s.%s", rrp->name, rrp->origin);
  381.             cp = dn_compress (cp, p);
  382.             free (p);
  383.         } else
  384. #endif
  385.             cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
  386.         cp = put16 (cp, rrp->type);
  387.         cp = put16 (cp, rrp->class);
  388.         cp = put32 (cp, (uint32) rrp->ttl);
  389. #ifdef notdef
  390.         /* The length doesn't seem to be right for all types ! */
  391.         cp = put16 (cp, rrp->rdlength);
  392. #endif
  393.         p = cp;        /* This is where the length goes ! */
  394.         cp += 2;    /* Save the space for lenght field */
  395.  
  396.         switch (rrp->type) {
  397.             case TYPE_A:
  398.                 cp = put32 (cp, rrp->rdata.addr);
  399.                 break;
  400.             case TYPE_SOA:
  401.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.mname);
  402.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.rname);
  403.                 cp = put32 (cp, (uint32) rrp->rdata.soa.serial);
  404.                 cp = put32 (cp, (uint32) rrp->rdata.soa.refresh);
  405.                 cp = put32 (cp, (uint32) rrp->rdata.soa.retry);
  406.                 cp = put32 (cp, (uint32) rrp->rdata.soa.expire);
  407.                 cp = put32 (cp, (uint32) rrp->rdata.soa.minimum);
  408.                 break;
  409.             case TYPE_HINFO:
  410.                 len = (int) strlen (rrp->rdata.hinfo.cpu);
  411.                 *cp++ = uchar(len);
  412.                 strncpy ((char *) cp, rrp->rdata.hinfo.cpu, (size_t) len);
  413.                 cp += len;
  414.                 len = (int) strlen (rrp->rdata.hinfo.os);
  415.                 *cp++ = uchar(len);
  416.                 strncpy ((char *) cp, rrp->rdata.hinfo.os, (size_t) len);
  417.                 cp += len;
  418.                 break;
  419.             case TYPE_MX:
  420.                 cp = put16 (cp, rrp->rdata.mx.pref);
  421.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.mx.exch);
  422.                 break;
  423.             case TYPE_CNAME:
  424.             case TYPE_MB:
  425.             case TYPE_MG:
  426.             case TYPE_MR:
  427.             case TYPE_NS:
  428.             case TYPE_PTR:
  429.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
  430.                 break;
  431.             case TYPE_MINFO:    /* Unsupported type */
  432.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.rmailbx);
  433.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.emailbx);
  434.                 /* fall through */
  435.             case TYPE_MD:    /* Unsupported type */
  436.             case TYPE_MF:    /* Unsupported type */
  437.             case TYPE_NULL:/* Unsupported type */
  438.             case TYPE_WKS:    /* Unsupported type */
  439.                 cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
  440.                 break;
  441.             case TYPE_TXT:
  442.             default:
  443.                 cp = put16 (cp, rrp->rdlength);
  444.                 for (i = 0; i < rrp->rdlength; i++)
  445.                     *cp++ = uchar(rrp->rdata.data[i]);
  446.                 break;
  447.         }
  448.         /* Calculate the lenght of the RR */
  449.         len = cp - p - 2;
  450.         (void) put16 (p, (int16) len);    /* and set it */
  451.     }
  452.     return (char *) cp;
  453. }
  454.  
  455.  
  456. int
  457. htondomain (dhdr, buffer, buflen)
  458. struct dhdr *dhdr;
  459. char *buffer;            /* Area for query */
  460. int16 buflen OPTIONAL;            /* Length of same */
  461. {
  462. unsigned char *cp;
  463. struct rr *rrp;
  464. int16 parameter;
  465. int i, count;
  466. int done = 0;
  467.  
  468.     cp = (unsigned char *) buffer;
  469.     cp = put16 (cp, dhdr->id);
  470.     if (dhdr->qr)
  471.         parameter = 0x8000;
  472.     else
  473.         parameter = 0;
  474.     parameter |= (dhdr->opcode & 0x0f) << 11;
  475.     if (dhdr->aa)
  476.         parameter |= DOM_AUTHORITY;
  477.     if (dhdr->tc)
  478.         parameter |= DOM_TRUNC;
  479.     if (dhdr->rd)
  480.         parameter |= DOM_DORECURSE;
  481.     if (dhdr->ra)
  482.         parameter |= DOM_CANRECURSE;
  483.     parameter |= (dhdr->rcode & 0x0f);
  484.     cp = put16 (cp, parameter);
  485.     cp = put16 (cp, dhdr->qdcount);
  486.     cp = put16 (cp, dhdr->ancount);
  487.     cp = put16 (cp, dhdr->nscount);
  488.     cp = put16 (cp, dhdr->arcount);
  489.     if ((count = dhdr->qdcount) > 0) {
  490.         rrp = dhdr->questions;
  491.         for (i = 0; i < count; i++) {
  492.             cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
  493.             cp = put16 (cp, rrp->type);
  494.             cp = put16 (cp, rrp->class);
  495.             rrp = rrp->next;
  496.         }
  497.     }
  498.  
  499.     if (((char *) cp - buffer) > buflen)
  500.         done = 1;
  501.  
  502.     if (!done && (count = dhdr->ancount) > 0) {
  503.         rrp = dhdr->answers;
  504.         for (i = 0; i < count; i++) {
  505.             cp = (unsigned char *) htonrr (rrp, (char *) cp);
  506.             if (((char *) cp - buffer) > buflen)    {
  507.                 done = 1;
  508.                 break;
  509.             }
  510.             rrp = rrp->next;
  511.         }
  512.     }
  513.     if (!done && (count = dhdr->nscount) > 0) {
  514.         rrp = dhdr->authority;
  515.         for (i = 0; i < count; i++) {
  516.             cp = (unsigned char *) htonrr (rrp, (char *) cp);
  517.             if (((char *) cp - buffer) > buflen)    {
  518.                 done = 1;
  519.                 break;
  520.             }
  521.             rrp = rrp->next;
  522.         }
  523.     }
  524.     if (!done && (count = dhdr->arcount) > 0) {
  525.         rrp = dhdr->additional;
  526.         for (i = 0; i < count; i++) {
  527.             cp = (unsigned char *) htonrr (rrp, (char *) cp);
  528.             if (((char *) cp - buffer) > buflen)    {
  529.                 done = 1;
  530.                 break;
  531.             }
  532.             rrp = rrp->next;
  533.         }
  534.     }
  535.     return ((char *) cp - buffer);
  536. }
  537.  
  538. #endif /* DSERVER */
  539.